#include "stdafx.h"
#include "ALGORITHM.h"

// IDMAlgorithmMetadata : (static) function implementation

/*static*/ HRESULT  ALGORITHM::GetServiceType(
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ ULONG *out_pServiceTypeID)
{
	// Populate out_pServiceTypeID with a bitfield that describes the
	// mining service types. 
	//
	// The flags are defined in "oledbdm.h": OR together the 
	// appropriate combination.
	
	// DM_SERVICETYPE_CLASSIFICATION	
	// DM_SERVICETYPE_CLUSTERING	
	// DM_SERVICETYPE_ASSOCIATION	
	// DM_SERVICETYPE_DENSITY_ESTIMATE
	// DM_SERVICETYPE_SEQUENCE	
    
	*out_pServiceTypeID	= 0;
	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetServiceName( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ DMString *io_pstrServiceName)
{
	// MINING_SERVICES Schema Rowset column: SERVICE_NAME
	//
	// The name of the algorithm. Provider-specific. This will 
	// be used as the service identifier in the language. 
	// (It is not localizable.)
	//
	// The name must be a valid XML element name, which means it 
	// is restricted to one "word" and cannot contain any special
	// characters.
    
	static const LPWSTR szName	=	L"MyCompany_Pairwise_Linear_Regression";

	// Use the string handling from IDMContextServices to copy
	// your algorithm name to io_pstrServiceName;
	CComPtr<IDMStringHandler> spidmstringhandler;
	HRESULT hr	= in_pContext->GetStringHandler(&spidmstringhandler);
	RETURN_ON_FAIL(hr);

	return spidmstringhandler->CopyBufferToHandle(io_pstrServiceName, 
											      szName, 
											      (UINT) wcslen(szName));
}

/*static*/ HRESULT  ALGORITHM::GetDisplayName( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ DMString *io_pstrDisplayName)
{
	// MINING_SERVICES Schema Rowset column: SERVICE_DISPLAY_NAME 
	
	// The localizable display name of the algorithm.

	// ToDo: change -1 to the resource ID for the string containing the 
	// display name

	static const int	iIDStrAlgorithm = -1;	// Resource ID for the string containing the
												// display name

	static const int	cchMaxDisplay	= 2000;

	WCHAR	szDisplay[cchMaxDisplay + 1];

	// Get the locale from the context-services interface 

	LCID lcid;

	HRESULT hr = in_pContext->GetContextLocaleID(&lcid);

	RETURN_ON_FAIL(hr);

	// Get the display name using the resource ID and locale
	
	hr = ::LoadStringFromID(iIDStrAlgorithm, lcid, szDisplay, cchMaxDisplay);

	RETURN_ON_FAIL(hr);

	// Grab a string handler to copy szDisplay to the output

	CComPtr<IDMStringHandler> spidmstringhandler;	// Smart pointer for a string handler

	hr	= in_pContext->GetStringHandler(&spidmstringhandler);

	RETURN_ON_FAIL(hr);

	return spidmstringhandler->CopyBufferToHandle(io_pstrDisplayName, 
												  szDisplay, 
												  (UINT)wcslen(szDisplay));
}

/*static*/ HRESULT  ALGORITHM::GetServiceGuid( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ GUID *out_pguidServiceGUID)
{
	// GUID that uniquely identifies the algorithm. 
	//*out_pguidServiceGUID = CLSID_ALGORITHM;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetDescription( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ DMString *io_pstrDescription)
{
	// MINING_SERVICES Schema Rowset column: DESCRIPTION
	
	// Human-readable description of the algorithm.

	// ToDo: change -1 to the resource ID for the string containing the 
	// algorithm description

	static const int	iIDStrDescription = -1;		// Resource ID for the string containing the
													// algorithm's description

	static const int	cchMaxDescription = 2000;

	WCHAR	szDescription[cchMaxDescription + 1];

	// Get the locale from the context-services interface 

	LCID lcid;

	HRESULT hr = in_pContext->GetContextLocaleID(&lcid);

	RETURN_ON_FAIL(hr);

	// Get the description using the resource ID and locale
	
	hr = ::LoadStringFromID(iIDStrDescription, lcid, szDescription, cchMaxDescription);

	RETURN_ON_FAIL(hr);

	// Grab a string handler to copy szDescription to the output

	CComPtr<IDMStringHandler> spidmstringhandler;	// Smart pointer for a string handler

	hr	= in_pContext->GetStringHandler(&spidmstringhandler);

	RETURN_ON_FAIL(hr);

	return spidmstringhandler->CopyBufferToHandle(io_pstrDescription, 
												  szDescription, 
												  (UINT)wcslen(szDescription));
}


/*static*/ HRESULT  ALGORITHM::GetPredictionLimit(
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ LONG *out_pPredictionLimit)
{
	// MINING_SERVICES Schema Rowset column: PREDICTION_LIMIT
	//
	// The maximum number of predictions the model and algorithm 
	// can provide; 0 means no limit. In most cases, this should
	// be no limit.

	*out_pPredictionLimit = 0;
	
	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetSupDistributionFlags( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ ULONG **out_prgFlags,
    /* [out] */ ULONG *out_cFlags)
{
	// MINING_SERVICES Schema Rowset column: SUPPORTED_DISTRIBUTION_FLAGS

	*out_prgFlags = NULL;
	*out_cFlags	  =	0;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetSupInputContentTypes( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ ULONG **out_prgTypes,
    /* [out] */ ULONG *out_cTypes)
{
	// MINING_SERVICES Schema Rowset column: SUPPORTED_INPUT_CONTENT_TYPES 

	// An array of one or more of the allowed column-content types for the
	// input variables. You should always include
	//
	//		DM_MININGCOLUMN_CONTENT_KEY
	//
	// as a supported "input content", even though the Key is typically not
	// an input variable; in this context, "input" means "not output".
	//
	// Simply un-comment the other ones that are appropriate to your algorithm.

	static ULONG	rgminingmodelcontentInputTypes[] = 
	{		
		(ULONG) DM_MININGCOLUMN_CONTENT_KEY,
	//  (ULONG) DM_MININGCOLUMN_CONTENT_DISCRETE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_CONTINUOUS,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_DISCRETIZED,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_SEQUENCETIME,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_ORDERED,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_CYCLICAL,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_NESTEDTABLE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_KEY_SEQUENCE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_KEY_TIME,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_PROBABILITY,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_VARIANCE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_STDDEV,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_SUPPORT,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_PROBABILITYVARIANCE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_PROBABILITYSTDDEV
	};

	static const ULONG cminingmodelcontentInputTypes = 
		sizeof(rgminingmodelcontentInputTypes)/sizeof(ULONG);
	
	*out_prgTypes	= rgminingmodelcontentInputTypes;
	*out_cTypes		= cminingmodelcontentInputTypes;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetSupPredictContentTypes( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ ULONG **out_prgTypes,
    /* [out] */ ULONG *out_cTypes)
{
	// MINING_SERVICES Schema Rowset column: SUPPORTED_PREDICTION_CONTENT_TYPES 

	// Same as above but for the output variable(s) - in this case you only 
	// want to include DM_MININGCOLUMN_CONTENT_KEY if your model uses the Key
	// as an output variable, which is not often the case. The 
	// DM_MININGCOLUMN_CONTENT_DISCRETE option is not commented below simply
	// so that this file will compile with minimal modification; only leave
	// this uncommented if your model supports discrete-variable outputs.

	static ULONG	rgminingmodelcontentOutputTypes[] = 
	{		
		(ULONG) DM_MININGCOLUMN_CONTENT_DISCRETE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_CONTINUOUS,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_DISCRETIZED,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_SEQUENCETIME,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_ORDERED,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_CYCLICAL,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_NESTEDTABLE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_KEY,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_KEY_SEQUENCE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_KEY_TIME,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_PROBABILITY,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_VARIANCE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_STDDEV,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_SUPPORT,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_PROBABILITYVARIANCE,
	//	(ULONG) DM_MININGCOLUMN_CONTENT_PROBABILITYSTDDEV
	};

	static const ULONG cminingmodelcontentOutputTypes = 
		sizeof(rgminingmodelcontentOutputTypes)/sizeof(ULONG);
	
	*out_prgTypes	= rgminingmodelcontentOutputTypes;
	*out_cTypes		= cminingmodelcontentOutputTypes;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetSupModelingFlags( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ DM_MODELING_FLAG **out_prgFlags,
    /* [out] */ ULONG *out_pcFlags)
{
	// MINING_SERVICES Schema Rowset column: SUPPORTED_MODELING_FLAGS 
	

	*out_prgFlags = NULL;
	*out_pcFlags = 0;
	
	return S_OK;
}


/*static*/ HRESULT  ALGORITHM::GetModelingFlagName( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in]  */ DM_MODELING_FLAG in_Flag,
    /* [out] */ DMString *io_pstrFlagName)
{
	// Return the name of the flag.
	io_pstrFlagName = NULL;

	return S_OK;
}


/*static*/ HRESULT  ALGORITHM::GetTrainingComplexity( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ LONG *out_pTrainingComplexity)
{
	// MINING_SERVICES Schema Rowset column: TRAINING_COMPLEXITY

	// Indication of expected time for training:
	//
	// DM_TRAINING_COMPLEXITY_LOW : 
	// Running time is proportional to input and is relatively short.
	//
	// DM_TRAINING_COMPLEXITY_MEDIUM : 
	// Running time may be long but is generally proportional to input. 
	//
    // DM_TRAINING_COMPLEXITY_HIGH : 
	// Running time is long and may grow exponentially in relationship to input.

	//	*out_pTrainingComplexity = DM_TRAINING_COMPLEXITY_XXXX;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetPredictionComplexity( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ LONG *out_pPredictionComplexity)
{
	// MINING_SERVICES Schema Rowset column: PREDICTION_COMPLEXITY

	// Indication of expected time for prediction:
	//
	// DM_PREDICTION_COMPLEXITY_LOW : 
	// Running time is proportional to input and is relatively short.
	// 
	// DM_PREDICTION_COMPLEXITY_MEDIUM : 
	// Running time may be long but is generally proportional to input. 
	//
	// DM_ PREDICTION_COMPLEXITY_HIGH : 
	// Running time is long and may grow exponentially in relationship to input.

	// *out_pPredictionComplexity = DM_PREDICTION_COMPLEXITY_XXXX;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetExpectedQuality( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ LONG *out_pExpectedQuality)
{
	// MINING_SERVICES Schema Rowset column: EXPECTED_QUALITY

	// You need not set this
	// parameter.

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetScaling( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ LONG *out_pScaling)
{
	// MINING_SERVICES Schema Rowset column: SCALING
	
	// You need not set this
	// parameter.

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetAllowIncrementalInsert( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ BOOL *out_pfIncrementalInsert)
{
	// MINING_SERVICES Schema Rowset column: ALLOW_INCREMENTAL_INSERT

	// Return TRUE if you allow incremental insert.  The engine
	// does not support this, and thus the value should be false.

	*out_pfIncrementalInsert = FALSE;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetAllowDuplicateKey( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ BOOL *out_pfDuplicateKey)
{
	// MINING_SERVICES Schema Rowset column: ALLOW_DUPLICATE_KEY

	// True if cases may have duplicate key. The engine
	// does not support this, and thus the value should be false.

	*out_pfDuplicateKey = FALSE;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetControl( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ LONG *out_pControl)
{
	// MINING_SERVICES Schema Rowset column: CONTROL


	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetViewerType( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ DMString *io_pstrViewerType)
{
	// Returns the name of the viewer that will be used to view
	// this model. The built-in viewers are

	// DM_VIEWERTYPE_MICROSOFT_TREE                
	// DM_VIEWERTYPE_MICROSOFT_CLUSTER             
	// DM_VIEWERTYPE_MICROSOFT_SEQUENCE_CLUSTER    
	// DM_VIEWERTYPE_MICROSOFT_TIME_SERIES         
	// DM_VIEWERTYPE_MICROSOFT_NAIVEBAYESIAN       
	// DM_VIEWERTYPE_MICROSOFT_ASSOCIATION_RULES   
	// DM_VIEWERTYPE_MICROSOFT_NEURAL_NETWORK      

	// Example of how to specify the decision-tree viewer
	/*
	static const LPWSTR szViewer	=	DM_VIEWERTYPE_MICROSOFT_TREE;

	CComPtr<IDMStringHandler> spidmstringhandler;
	
	HRESULT hr	= in_pContext->GetStringHandler(&spidmstringhandler);

	RETURN_ON_FAIL(hr);

	return spidmstringhandler->CopyBufferToHandle(io_pstrViewerType, 
												  szViewer, 
												  (UINT)wcslen(szViewer));
	*/
	return S_OK;
}


/*static*/ HRESULT  ALGORITHM::GetSupportsDMDimensions( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ BOOL *out_pfSupportsDMDimensions)
{
	// Specifies whether or not the content of the trained model can be organized 
	// as a browsable hierarchy. 

	// If your algorithm does not support DM Dimensions, just populate the output 
	// variable with FALSE and return S_OK

	*out_pfSupportsDMDimensions = FALSE;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetSupportsDrillthrough( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ BOOL *out_pfSupportsDrillthrough,
    /* [out] */ BOOL *out_pfMustIncludeChildren)
{
	// Specifies whether or not the model will retain references to the original cases
	// to be displayed while browsing. If you support drillthrough, the parameter
	// out_pfMustIncludeChildren is FALSE if the cases stored in a navigation node
	// contain the cases corresponding to all descendants of that node. 

	*out_pfSupportsDrillthrough = FALSE;
	*out_pfMustIncludeChildren = TRUE;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetSupportedFunctions( 
        /* [in] */ IDMContextServices *in_pContext,
        /* [out] */ DM_SUPPORTED_FUNCTION **out_prgFuncs,
        /* [out] */ ULONG *out_cFuncs)
{
	// A "well-known function" call during prediction (like select 
	// PredictHistogram) translates to a Predict call with some specific 
	// flags.
	// 
	// Here, the service (i.e. your algorithm) reports which such flag 
	// combinations are supported, and therefore which prediction functions are 
	// supported. This is also used in populating the prediction_scalar_functions 
	// and prediction_table_functions of the MINING_MODELS schema rowset
	//
	// The possible values are given by the DM_SUPPORTED_FUNCTION_ENUM enumeration in 
	// dmalgo.h, and are listed below. You may comment out the functions that
	// you do not support so that an error is returned when someone tries to 
	// call that function with your algorithm. 
	//
	// It is probably easiest to simply leave these all defined as-is, and then
	// return an error on the Predict() call if you get a combination of
	// flags that you do not support.

	static const DM_SUPPORTED_FUNCTION_ENUM	rgdmfuncmap[]	=	
	{
		DMSF_Predict_Scalar,
		DMSF_Predict_Table,
		DMSF_PredictAssociation,
		DMSF_PredictSequence,
		DMSF_PredictTimeSeries,
		DMSF_PredictSupport,
		DMSF_PredictVariance,
		DMSF_PredictStdev,
		DMSF_PredictProbablility,
		DMSF_PredictAdjustedProbability,
		DMSF_Cluster,
		DMSF_ClusterDistance,
		DMSF_ClusterProbability,
		DMSF_PredictHistogram,
		DMSF_ClusterPredictHistogram,
		DMSF_TopCount,
		DMSF_BottomCount,
		DMSF_TopSum,
		DMSF_BottomSum,
		DMSF_TopPercent,
		DMSF_BottomPercent,
		DMSF_RangeMid,
		DMSF_RangeMin,
		DMSF_RangeMax,
		DMSF_PredictNodeId,
		DMSF_IsInNode,
		DMSF_IsDescendent,
		DMSF_DCluster,
		DMSF_DProbability,
		DMSF_DAdjustedProbability,
		DMSF_DStdev,
		DMSF_DSupport,
		DMSF_DVariance,
		DMSF_DNodeId,
		DMSF_DSequence,
		DMSF_DTime,
		DMSF_DDistance,
		DMSF_Lag,
		DMSF_PredictCaseLikelihood
    };

	static const ULONG cdmfuncmap = sizeof(rgdmfuncmap)/sizeof(DM_SUPPORTED_FUNCTION_ENUM);

	*out_prgFuncs	=	(DM_SUPPORTED_FUNCTION*)&rgdmfuncmap;
	*out_cFuncs		=	cdmfuncmap;

	return S_OK;
}

////////
//
// Parameter Functions:
// --------------------
//
// The stubs below assume that you are using the default parameter-handling mechanistm, 
// in which case your algorithm class will contain a static DMHPARAMHANDLER member that 
// does almost all of the work of these functions for you. If you are not using this mechanism,
// simply delete the call to the corresponding DMHPARAMHANDLER function and replace with
// your own implementation.
//
// See DmhParameters.h to see how the default parameter-handling mechanism is used.
//
// 
////////

/*static*/ HRESULT  ALGORITHM::GetNumParameters( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ ULONG *out_pcParameters)
{
	// Tells the caller the number of parameters that can be passed to your
	// algorithm.

	return _dmhparamhandler.GetNumParameters(in_pContext, out_pcParameters);
}

/*static*/ HRESULT  ALGORITHM::GetParameterName( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [out] */ DMString *io_pstrParameterName)
{
	return _dmhparamhandler.GetParameterName(in_pContext, in_iParameter, io_pstrParameterName);
}

/*static*/ HRESULT  ALGORITHM::GetParameterType( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [out] */ DMString *io_pstrParameterType)
{
	// The type strings should be the same as the enumeration names of DBTYPEENUM (oledb.h)
	// for the scalar numeric types:
	
	/*
	DBTYPE_I2
	DBTYPE_I4
	DBTYPE_R4
	DBTYPE_R8
	DBTYPE_BOOL
	DBTYPE_UI2
	DBTYPE_UI4
	DBTYPE_I8
	DBTYPE_UI8
	*/

	return _dmhparamhandler.GetParameterType(in_pContext, in_iParameter, io_pstrParameterType);
}

/*static*/ HRESULT  ALGORITHM::GetParameterIsRequired( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [out] */ BOOL *out_pfIsRequired)
{
	return _dmhparamhandler.GetParameterIsRequired(in_pContext, in_iParameter, out_pfIsRequired);
}


/*static*/ HRESULT  ALGORITHM::GetParameterIsExposed( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [out] */ BOOL *out_pfIsExposed)
{
	return _dmhparamhandler.GetParameterIsExposed(in_pContext, in_iParameter, out_pfIsExposed);
}


/*static*/ HRESULT  ALGORITHM::GetParameterFlags( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [out] */ ULONG *out_pulParameterFlags)
{
	return _dmhparamhandler.GetParameterFlags(in_pContext, in_iParameter, out_pulParameterFlags);
}

/*static*/ HRESULT  ALGORITHM::GetParameterDescription( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [in] */ ULONG in_LocaleID,
    /* [out] */ DMString *io_pstrDescription)
{
	return _dmhparamhandler.GetParameterDescription(in_pContext, in_iParameter, in_LocaleID, io_pstrDescription);
}

/*static*/ HRESULT  ALGORITHM::GetParameterDefaultValue( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [out] */ DMString *io_pstrDefaultValue)
{
	return _dmhparamhandler.GetParameterDefaultValue(in_pContext, in_iParameter, io_pstrDefaultValue);
}

/*static*/ HRESULT  ALGORITHM::GetParameterValueEnumeration( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [out] */ DMString *io_pstrValueEnumeration)
{
	// This is a user-friendly representation of the valid
	// values for the parameter (i.e. "(0,1]"). 

	return _dmhparamhandler.GetParameterValueEnumeration(in_pContext, in_iParameter, io_pstrValueEnumeration);
}


/*static*/ HRESULT  ALGORITHM::ParseParameterValue( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ ULONG in_iParameter,
    /* [in] */ DMString* in_pstrParameterStrValue,
    /* [in] */ DMVariantPtr io_pParameterMappedValue)
{
	// The default parameter-handling mechanism can convert strings into numeric values. 
	// If you want to handle more complicated parameter values (such as arrays), 
	// check for the HRESULT returned by the AGPARAMHANDLER: it will be S_FALSE if the current
	// parameter was not a simple numeric type.

	HRESULT hr = _dmhparamhandler.ParseParameterValue(in_pContext,
													  in_iParameter,
													  in_pstrParameterStrValue,
													  io_pParameterMappedValue);

	if (hr == S_FALSE)
	{
        // Specialty parsing here if in_iParameter is not numeric
	}

	return hr;
}

/*static*/ HRESULT  ALGORITHM::GetMarginalRequirements( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [out] */ DMMarginalRequirements *out_pReq)
{
	// This method lets the engine know whether the plug-in algorithm will
	// need any statistics. If the return value is populated with DMMR_NONE, 
	// the IDMMarginalStat* (3rd) parameter of IDMAlgorithm::Initialize will 
	// be NULL.

	// You should populate the out_Req with one (or a bitmask combination) 
	// of the following values

	/*
	DMMR_NONE
	DMMR_INPUT_STATS
	DMMR_OUTPUT_STATS
	DMMR_ALL_STATS  = DMMR_INPUT_STATS | DMMR_OUTPUT_STATS
	*/

	*out_pReq = DMMR_NONE;

	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::GetSupportsPMML( 
            /* [in] */ IDMContextServices *in_pContext,
            /* [out] */ BOOL *out_pfSupportsPMML)
{
	// Set to TRUE if your model supports PMML, FALSE otherwise
	*out_pfSupportsPMML = FALSE;
	return S_OK;
}


/*static*/ HRESULT  ALGORITHM::GetCaseIDModelled(
	/* [in] */ IDMContextServices *in_pContext,
	/* [out] */ BOOL *out_pfIsModelled)
{
	// Set to TRUE if your model is treating the case ID as a separate
	// variable.

	*out_pfIsModelled = FALSE;
	return S_OK;
}

/*static*/ HRESULT  ALGORITHM::ValidateAttributeSet( 
	/* [in]  */	IDMContextServices* in_pContext,
    /* [in] */ IDMAttributeSet *in_pAttributeSet)
{
	// Check whether or not the attribute set is appropriate for the
	// learning algorithm.

	return S_OK;
}